/*
 * Copyright (c) Huawei Technologies Co., Ltd. 2021-2022. All rights reserved.
 *
 */

import fs from 'fs';
import os from 'os';
import * as path from 'path';

import {
  FileSet,
  hash,
  hvigorCore,
  isLinux,
  isMac,
  isWindows,
  Json5Reader,
  parseJsonFile,
  TaskInputValue,
  DEFAULT_HVIGOR_CONFIG_JSON_FILE_NAME,
  HVIGOR_PROJECT_WRAPPER_HOME
} from '@ohos/hvigor';
import { FsOptions } from '@ohos/hvigor/src/base/internal/snapshot/util/file-set';
import * as fse from 'fs-extra';

import { buildOptionPath } from '../common/build-option-path-info.js';
import { parsingProfileName } from '../common/common-util.js';
import { moduleOhosConfigManager } from '../common/global/module-ohos-config-manager.js';
import { projectOhosConfigManager } from '../common/global/project-ohos-config-manager.js';
import { moduleDependencyUtil } from '../common/module-dependency-util.js';
import { moduleOptionPathInfo } from '../common/module-option-path-info.js';
import { ohosTrace } from '../common/trace/ohos-trace.js';
import { BuildArtifactConst, BuildDirConst } from '../const/build-directory-const.js';
import {
  ArkTSVersionConst,
  BuildProfileSchemaFileConst,
  BundleType,
  CommonConst,
  DefaultTargetConst,
  ValidateRegExp,
} from '../const/common-const.js';
import { InjectConst } from '../const/inject-const.js';
import { ApiVersion } from '../const/sdk-const.js';
import { ModuleType } from '../enum/module-type-enum.js';
import { JsonProfile } from '../model/json-profile.js';
import { ProjectModelImpl } from '../model/project/project-model-impl.js';
import { TargetSourceSetModel } from '../model/source-set/source-set-model.js';
import { TargetSourceSetImpl } from '../model/source-set/target-source-set-impl.js';
import { ProjectBuildProfile } from '../options/build/project-build-profile.js';
import { AppJson } from '../options/configure/app-json-options.js';
import { FormConfigJson } from '../options/configure/form-json-options.js';
import { ModuleJson } from '../options/configure/module-json-options.js';
import { ApiType } from '../project/data/hap-extra-info.js';
import { Dependency, DependencyType } from '../project/dependency/core/dependency-interface.js';
import { DependencyManager } from '../project/dependency/dependency-manager.js';
import { getUnionSet, isSubset } from '../utils/array-util.js';
import { getRuntimeOnlyObjMap } from '../utils/build-profile-utils.js';
import { checkByteCodeHar } from '../utils/byte-code-har-utils.js';
import { FileUtil } from '../utils/file-util.js';
import { InjectUtil } from '../utils/inject-util.js';
import { getJson5Obj } from '../utils/json-util.js';
import { resModelLoader } from '../utils/loader/file/res-model-loader.js';
import { OhosLogger } from '../utils/log/ohos-logger.js';
import { getMockConfigSources } from '../utils/mock-config-utils.js';
import { isTemplatesAfterSourceCodeMigration } from '../utils/ohos-test-util.js';
import { limitMinApiVersion } from '../utils/task-util.js';
import { handleStartWindowErrors, removeLegacyPhoneSupport } from '../utils/validate/error-handlers.js';
import {
  validateOhosHarModuleConfig,
  validateOhosModuleConfig,
  validateOhosProjectConfig
} from '../utils/validate/validate-config.js';
import { ValidateUtil } from '../utils/validate/validate-util.js';
import { AbstractPreBuild } from './abstract/abstract-pre-build.js';
import { TaskNames } from './common/task-names.js';
import { TargetTaskService } from './service/target-task-service.js';

import ModuleOptObj = ModuleJson.ModuleOptObj;
import Task = TaskNames.Task;
import { pacFileValidate } from "../utils/pac-util";

const _log = OhosLogger.getLogger('hvigor-preBuild');

interface IExtendSourceValidateResult {
  isValid: boolean;
  cause: string;
  detail: string;
}

/**
 * preBuild Task
 *
 * @since 2022/1/10
 */
export class PreBuild extends AbstractPreBuild {
  // 常量
  protected readonly INSIGHT_INTENT_SRC_ENTRY = 'insightIntent-srcEntry';
  protected readonly MODULE_SRC_ENTRY = 'module-srcEntry';
  protected readonly MODULE_ABILITIES_SRC_ENTRY = 'module-abilities-srcEntry';
  protected readonly MODULE_EXTENSION_ABILITIES_SRC_ENTRY = 'module-extensionAbilities-srcEntry';
  // project相关属性
  protected readonly insightIntentJsonPath: string;
  // target相关属性
  protected readonly targetJsonPath: string;
  protected isPreview: boolean | undefined;

  // project相关属性
  private readonly appJson5Path: string;
  private readonly arkDataPath: string;
  private readonly utdPath: string;
  private readonly hvigorConfigPath: string;

  // target相关属性
  private readonly targetModuleOptObj: ModuleOptObj | undefined;
  private readonly resourcePath: string;
  private readonly pagesJsonPath: string | undefined;
  private readonly systemThemeJsonPath: string | undefined;
  private readonly startWindowJsonPathArr: string[];
  private readonly formJsonPathArr: string[];
  private readonly routerMapJsonPath: string | undefined;
  private readonly shortcutsJsonPaths: string[];
  private readonly extendSourceValidateResult: IExtendSourceValidateResult;
  private readonly originalModulePacJsonPath: string;
  private readonly processedPacJsonPath: string;
  private readonly processedPacJsonDir: string;

  declareInputs(): Map<string, TaskInputValue> {
    let declareInputsMap = super.declareInputs();
    const moduleDependenciesList = Object.keys(this.getDependencies(this.moduleModel, false));
    const projectDependenciesList = Object.keys(this.getDependencies(this.projectModel, false));
    const runtimeOnlyObjMap = getRuntimeOnlyObjMap(
      this.module.getNodeDir(),
      this.targetService.getBuildOption()?.arkOptions?.runtimeOnly,
      getUnionSet(moduleDependenciesList, projectDependenciesList),
    );
    for (const [key, value] of runtimeOnlyObjMap) {
      declareInputsMap.set(key, value);
    }
    const projectConfig = projectOhosConfigManager.getConfig();
    if (projectConfig) {
      declareInputsMap.set('appHvigorFileConfig', hash(JSON.stringify(projectConfig)));
    }
    const config = moduleOhosConfigManager.getConfig(this.moduleName);
    if (config) {
      declareInputsMap.set('moduleHvigorFileConfig', hash(JSON.stringify(config)));
    }

    this.formJsonPathArr.forEach((formConfigJson: string) => {
      const formConfigObj: FormConfigJson.FormConfigJsonObj = parseJsonFile(formConfigJson, false);
      if (formConfigObj.forms) {
        formConfigObj.forms.forEach((form) => {
          if (form.src) {
            const widgetSrc =
              form.uiSyntax === 'arkts'
                ? path.resolve(this.moduleModel.getProjectDir(), 'src/main', form.src)
                : path.resolve(this.moduleModel.getProjectDir(), 'src/main', `${form.src}.json`);
            if (fs.existsSync(widgetSrc)) {
              declareInputsMap.set(form.src, widgetSrc);
            }
          }
        });
      }
    });
    declareInputsMap.set(CommonConst.USE_NORMALIZED_OHM_URL, !!this.targetService.getBuildOption()?.strictMode?.useNormalizedOHMUrl);
    declareInputsMap.set(BuildDirConst.INTEGRATED_HSP, !!this.targetService.getBuildOption().arkOptions?.integratedHsp);
    declareInputsMap.set('sourceRoots', this.extendSourceValidateResult.isValid);
    declareInputsMap.set(BuildDirConst.TRANSFORM_LIB, this.targetService.getBuildOption()?.arkOptions?.transformLib ?? '');
    declareInputsMap.set('byteCodeHar', !!this.targetService.getBuildOption()?.arkOptions?.byteCodeHar);
    declareInputsMap = this.addConfigurationToInput(declareInputsMap);
    // 不需要检测mock-config中的source的内容有没有变，只需要确定文件在不在即可
    // source内容的变更，不需要执行pre-build
    if (fse.existsSync(this.moduleModel.getMockConfigPath())) {
      declareInputsMap.set('mockConfigSources', getMockConfigSources(this.moduleModel.getMockConfigPath(), this.moduleModel.getProjectDir()).join(','));
    }
    return declareInputsMap;
  }

  declareInputFiles(): FileSet {
    const fileSet = new FileSet().addEntries([this.appJson5Path, this.targetJsonPath, ...this.formJsonPathArr, ...this.startWindowJsonPathArr], {
      isDirectory: false,
    });

    this.setIncrementalInput(fileSet, this.projectProfilePath);
    this.setIncrementalInput(fileSet, this.profilePath);
    this.setIncrementalInput(fileSet, this.appStartupPath);
    this.setIncrementalInput(fileSet, this.routerMapJsonPath);
    this.targetService.getWorkerConfig().forEach((workerPath) => {
      this.setIncrementalInput(fileSet, workerPath);
    });
    this.setIncrementalInput(fileSet, this.syscapJsonPath);
    this.setIncrementalInput(fileSet, this.pagesJsonPath);
    this.setIncrementalInput(fileSet, this.systemThemeJsonPath);
    this.setIncrementalInput(fileSet, this.insightIntentJsonPath);
    this.setIncrementalInput(fileSet, this.arkDataPath, { isDirectory: true });
    this.setIncrementalInput(fileSet, this.utdPath, { isDirectory: true });
    this.setIncrementalInput(fileSet, this.hvigorConfigPath, { isDirectory: true });
    this.setIncrementalInput(fileSet, this.moduleModel.getMockConfigPath(), { isDirectory: false });
    // 只关注Har和Hsp的pac文件
    if (!this.moduleModel.isHapModule()) {
      this.setIncrementalInput(fileSet, this.originalModulePacJsonPath);
    }

    // 如果对应的oh-package.json5或package.json文件不存在，则不放进输入文件中
    const modulePackageJsonPath = this.isOhpmProject ? this.moduleModel.getOhPackageJson5Path() : this.moduleModel.getPackageJsonPath();
    this.setIncrementalInput(fileSet, modulePackageJsonPath);

    // 补充工程级的oh-package.json5或package.json文件增量
    const projectPackageJsonPath = this.isOhpmProject ? this.projectModel.getOhPackageJson5Path() : this.projectModel.getPackageJsonPath();
    this.setIncrementalInput(fileSet, projectPackageJsonPath);
    return fileSet;
  }

  declareOutputFiles(): FileSet {
    const outPutFiles = new FileSet();
    outPutFiles.addEntry(this.processedPacJsonPath);
    return outPutFiles;
  }

  private setShortcutsJsonPathIncrementalInput(fileSet: FileSet) {
    if (!this.shortcutsJsonPaths) {
      return;
    }
    // 将用户配置的shortcuts文件加入增量判断
    this.shortcutsJsonPaths.forEach((shortcutsJsonPath) => {
      if (fse.existsSync(shortcutsJsonPath)) {
        fileSet.addEntry(shortcutsJsonPath);
      }
    });
  }

  /**
   * 设置增量输入
   * @param fileSet 文件集合
   * @param filePath 文件路径
   * @param options 文件系统选项，可选参数
   */
  private setIncrementalInput(fileSet: FileSet, filePath: string | undefined, options?: FsOptions | undefined) {
    // 检查文件路径是否存在
    if (filePath && fs.existsSync(filePath)) {
      // 如果文件路径存在，则将文件路径和选项添加到文件集合中
      fileSet.addEntry(filePath, options);
    }
  }

  constructor(taskService: TargetTaskService, taskName = Task.PRE_BUILD) {
    super(taskService, taskName);
    const appRes = (this.projectModel as ProjectModelImpl).getAppRes();
    this.appJson5Path = appRes.getJsonPath();
    const targetSourceSetModel: TargetSourceSetModel = taskService.getTargetData().getModuleSourceSetModel() as TargetSourceSetModel;
    const targetRes = targetSourceSetModel.getModuleTargetRes();
    this.targetJsonPath = targetRes.getJsonPath();
    this.targetModuleOptObj = targetRes.getModuleJsonOpt();
    this.formJsonPathArr = TargetTaskService.getFormJsonArr(targetRes);
    this.resourcePath = targetRes.getResourcePath();
    this.routerMapJsonPath = taskService.getRouterMapJsonPath(this.moduleModel);
    this.shortcutsJsonPaths = taskService.getShortcutsJsonPaths(this.moduleModel);

    // InsightIntent.json文件路径
    this.insightIntentJsonPath = path.resolve(
      taskService.getTargetData().getPathInfo().getModuleSrcMainResourceBaseProfilePath(),
      BuildArtifactConst.INSIGHT_INTENT_JSON,
    );
    this.pagesJsonPath = this.getPagesJsonPath();
    this.startWindowJsonPathArr = this.getStartWindowJsonPath();
    this.systemThemeJsonPath = this.getSystemThemeJsonPath();
    this.arkDataPath = path.resolve(taskService.getTargetData().getPathInfo().getModuleSrcMainResourceRawfileArkdataPath());
    this.utdPath = path.resolve(taskService.getTargetData().getPathInfo().getModuleSrcMainResourceRawfileUtdPath());
    this.hvigorConfigPath = path.resolve(HVIGOR_PROJECT_WRAPPER_HOME, DEFAULT_HVIGOR_CONFIG_JSON_FILE_NAME);

    this.isPreview = hvigorCore.getExtraConfig().get(InjectConst.BUILD_ROOT) === BuildDirConst.PREVIEW_BUILD_PATH;
    this.extendSourceValidateResult = this.getExtendSourceDirsValidateResult();
    this.processedPacJsonDir = this.pathInfo.getIntermediatesPacJsonDir();
    this.originalModulePacJsonPath = this.pathInfo.getPacJsonPath();
    this.processedPacJsonPath = this.pathInfo.getIntermediatesPacJsonPath();
    this.mockCacheClean();
  }

  protected doValidateForDiffApiType(): void {
    // app.json5 module.json5文件校验
    this.appJson5Validate();
    this.moduleJson5Validate();
    this.systemThemeJsonValidate();
    this.startWindowJsonValidate();
    this.formJsonValidate();
    this.pagesJsonValidate();
    this.routerMapJsonValidate();
    this.hvigorFileConfigValidate();
    this.sysCapValidate();
    this.hvigorConfigValidate();
    this.validateMockConfig();
    this.checkAppConfiguration();
    // pac.json5文件校验
    this.pacFileValidate();

    // insight_intent.json文件校验
    if (fs.existsSync(this.insightIntentJsonPath)) {
      this.buildProfileJsonValidate();
      this.insightIntentJsonValidate();
    }

    this.targetESVerisonValidate();

    // customerUtd校验
    if (fs.existsSync(this.utdPath)) {
      const utdFiles = fs.readdirSync(this.utdPath);
      if (utdFiles !== undefined && utdFiles.length > 0) {
        for (const utdFile of utdFiles) {
          const utdFilePath = path.resolve(this.utdPath, utdFile);
          this.utdJsonValidate(utdFilePath);
        }
      }
    }

    // arkdata.json的校验
    if (fs.existsSync(this.arkDataPath)) {
      const arkDataFiles = fs.readdirSync(this.arkDataPath);
      if (arkDataFiles !== undefined && arkDataFiles.length > 0) {
        for (const arkDataFile of arkDataFiles) {
          const arkDataFilePath = path.resolve(this.arkDataPath, arkDataFile);
          this.arkDataJsonValidate(arkDataFilePath);
        }
      }
    }

    // hsp无需校验
    if (this.service.getModuleModel()?.isHapModule()) {
      this.validateMainElement();
    }

    // 检查ohmUrl一致性
    this.checkOHMURL();

    // 检查dynamicImport配置
    this.checkDynamicImportFile();

    // 检查所有srcEntry配置
    this.checkAllSrcEntry();

    // 检查bundleDependencies配置
    this.checkBundledDependencies();

    // 检查当前api版本har/hsp是否支持UIAbility
    this.checkUIAbility();

    // 检查版本号和autoLazyImport是否匹配
    this.checkSdkVersionMatchLazyImport();

    // 检查元服务为单任务窗体，以及禁止声明隐式跳转

    // check dynamicDependency types
    this.checkDynamicDependencyTypes();

    // 检查excludeAppScopeRes是否在hap\har里面配置，配置的话需要给出warn
    this.checkIncludeAppScopeResInHapOrHar();
  }

  /**
   * 当存在.preview缓存时移动mock-config.json5配置文件，需要删除.preview中mock-config缓存文件
   * @protected
   */
  protected mockCacheClean() {
    const mockConfigPath = this.moduleModel.getMockConfigPath();
    if (!fse.existsSync(mockConfigPath) && this.isPreview) {
      const targetName = this.targetData.getTargetName();
      const pathInfo = this.targetData.getPathInfo();
      const modulePreviewPath = pathInfo.getModulePreviewPath();
      const previewIntermediatesResPath = pathInfo.getModulePreviewIntermediatesResPath();
      const cacheMockConfigJsonPath = path.resolve(modulePreviewPath, `cache/.${targetName}/mock-config.json`);
      if (fse.existsSync(cacheMockConfigJsonPath)) {
        fse.unlinkSync(cacheMockConfigJsonPath);
      }
      const cacheMockConfigJson5Path = path.resolve(modulePreviewPath, `cache/.${targetName}/mock-config.json5`);
      if (fse.existsSync(cacheMockConfigJson5Path)) {
        fse.unlinkSync(cacheMockConfigJson5Path);
      }
      const modulePreviewMockConfigJsonPath = path.resolve(previewIntermediatesResPath, 'mock-config.json');
      if (fse.existsSync(modulePreviewMockConfigJsonPath)) {
        fse.unlinkSync(modulePreviewMockConfigJsonPath);
      }
    }
  }

  protected targetESVerisonValidate() {
    const targetESVersion = this.targetService.getBuildOption()?.arkOptions?.tscConfig?.targetESVersion;
    if (targetESVersion) {
      if (this.compileApiVersion < ApiVersion.API_VERSION_12 || this.compatibleApiVersion < ApiVersion.API_VERSION_12) {
        _log.printErrorExit('UNSUPPORTED_API_VERSION_TARGET_ES_VERSION', [this.projectProfilePath]);
      }
    }
  }

  protected checkByteCodeHar() {
    if (!this.moduleModel.isHarModule()) {
      return;
    }

    const useNormalizedOHMUrl = this.targetService.getBuildOption()?.strictMode?.useNormalizedOHMUrl;
    const byteCodeHar = this.targetService.getByteCodeHar(useNormalizedOHMUrl, this.targetService.getBuildOption()?.arkOptions?.byteCodeHar);
    if (!byteCodeHar) {
      return;
    }

    checkByteCodeHar({
      logger: _log,
      useNormalizedOHMUrl,
      compileApiVersion: this.compileApiVersion,
      compatibleApiVersion: this.compatibleApiVersion,
    });
  }

  /**
   * 对compileSdkVersion和compatibleSdkVersion进行校验，对runtimeOS进行校验
   *
   * @protected
   */
  protected buildProfileJsonValidate() {
    if (this.compileApiVersion < ApiVersion.API_VERSION_11 || this.compatibleApiVersion < ApiVersion.API_VERSION_11) {
      _log.printErrorExit('UNSUPPORTED_API_VERSION_INSIGHT_INTENT', [this.targetJsonPath]);
    }
  }

  /**
   * insight_intent.json文件校验
   *
   * @protected
   */
  protected insightIntentJsonValidate() {
    const insightIntentSchemaPath: string = this.sdkInfo.getInsightIntentSchema();
    if (!fs.existsSync(insightIntentSchemaPath)) {
      _log.printErrorExit('UNSUPPORTED_SDK_VERSION_INSIGHT_INTENT', [this.targetJsonPath]);
    }
    ValidateUtil.submitSchemaCheckWork({
      moduleName: this.projectModel.getName(),
      filePath: this.insightIntentJsonPath,
      schemaPath: insightIntentSchemaPath,
    });
  }

  protected utdJsonValidate(utdFilePath: string) {
    const utdSchemaPath: string = this.sdkInfo.getUtdSchema();

    // 当utd的schema校验文件不存在时提示更新sdk
    if (!fs.existsSync(utdSchemaPath)) {
      _log.printErrorExit('UNSUPPORTED_SDK_VERSION_ARK_DATA', [this.targetJsonPath]);
    }

    ValidateUtil.submitSchemaCheckWork({
      moduleName: this.projectModel.getName(),
      filePath: utdFilePath,
      schemaPath: utdSchemaPath,
    });
  }

  protected arkDataJsonValidate(arkDataFilePath: string) {
    const arkDataSchemaPath: string = this.sdkInfo.getArkDataSchema();

    // 当arkdata的schema校验文件不存在时提示更新sdk
    if (!fs.existsSync(arkDataSchemaPath)) {
      _log.printErrorExit('UNSUPPORTED_SDK_VERSION_ARK_DATA', [this.targetJsonPath]);
    }

    ValidateUtil.submitSchemaCheckWork({
      moduleName: this.projectModel.getName(),
      filePath: arkDataFilePath,
      schemaPath: arkDataSchemaPath,
    });
  }

  protected appJson5Validate() {
    const appJson5SchemaPath = this.targetService.getSdkInfo().getAppSchema();

    // har包不校验icon与label字段
    const changeAppSchema = this.moduleModel.getModuleType() === ModuleType.Har;

    ValidateUtil.submitSchemaCheckWork({
      moduleName: this.projectModel.getName(),
      filePath: this.appJson5Path,
      schemaPath: appJson5SchemaPath,
      changeAppSchema,
    });
  }

  protected validateModuleSrcEntry(logger: OhosLogger, moduleJsonObj: ModuleJson.ModuleOptObj): void {
    const srcEntry = moduleJsonObj.module.srcEntry || moduleJsonObj.module.srcEntrance;
    if (srcEntry === undefined) {
      return;
    }
    const sourceSetModel = this.moduleModel.getSourceSetByTargetName(this.targetData.getTargetName());
    if (moduleJsonObj.module.srcEntry === undefined) {
      _log.warn(`Field "module.srcEntrance" has been deprecated. Use "module.srcEntry" instead.
      at ${(sourceSetModel as TargetSourceSetImpl).getModuleTargetRes().getJsonPath()}`);
    }
    const srcEntryPath = path.isAbsolute(srcEntry) ? srcEntry : path.resolve(sourceSetModel.getSourceSetRoot(), srcEntry);
    if (!FileUtil.fileExists(srcEntryPath)) {
      const targetSourceSet = sourceSetModel as TargetSourceSetImpl;
      _log.printErrorExit('MODULE_SRC_ENTRY_NOT_FOUND', [targetSourceSet.getModuleTargetRes().getJsonPath()]);
    }
  }

  protected moduleJson5Validate() {
    const target = this.targetName;
    const moduleJson5SchemaPath = this.targetService.getSdkInfo().getModuleSchema();
    ValidateUtil.submitSchemaCheckWork({
      moduleName: this.moduleName,
      filePath: this.targetJsonPath,
      schemaPath: moduleJson5SchemaPath,
      errorHandlers: [removeLegacyPhoneSupport, handleStartWindowErrors],
    });
    if (target !== DefaultTargetConst.OHOS_TEST_TARGET) {
      this.validateModuleName(this.moduleName, this.targetModuleOptObj!.module.name, CommonConst.MODULE_JSON5);
    }
    const moduleJson: ModuleOptObj = parseJsonFile(this.targetJsonPath, true);
    const moduleOptObj: ModuleOptObj = parseJsonFile(this.targetJsonPath, false);
    this.validateModuleSrcEntry(_log, getJson5Obj(this.targetJsonPath));
    if (moduleJson.module.uiSyntax === undefined && this.sdkInfo.requireUISyntax()) {
      _log.printErrorExit('UNSUPPORTED_SDK_VERSION_UI_SYNTAX', [this.targetJsonPath]);
    }
    ValidateUtil.validateHybridDeviceTypes(moduleJson.module.deviceTypes);
    ValidateUtil.validateDuplicatedName(moduleOptObj.module.abilities, 'ability', this.targetJsonPath);
  }

  /**
   * 校验dynamicImport配置中文件配置
   * 仅检查包名是否为本模块oh-package.json5中dependencies的子集;相对路径通过schema校验,且同时检查文件是否存在
   * @private
   */
  protected checkDynamicImportFile(): void {
    const runtimeOnlyObj = this.targetService.getBuildOption()?.arkOptions?.runtimeOnly;
    if (!runtimeOnlyObj) {
      return;
    }

    if (this.compileApiVersion < ApiVersion.API_VERSION_11 || this.apiType === ApiType.FA) {
      // dynamicImport仅支持api11+&stage工程
      _log.printErrorExit('UNSUPPORTED_API_VERSION_DYNAMIC_IMPORT', [this.moduleModel.getName(), CommonConst.PROFILE_JSON5, this.profilePath]);
    }

    if (runtimeOnlyObj.sources) {
      const noExternalImportByPath = this.targetService.isNoExternalImportByPath();
      const curModuleNodeDir = this.module.getNodeDir();
      const acrossModuleErrorPaths: string[] = [];
      const existFileErrorPaths: string[] = [];
      const suffixFileErrorPaths: string[] = [];
      const outsideModuleFileErrorPaths: string[] = [];
      const allModuleModelCwd: string[] = [];
      const runtimeOnlySrcCfgPath: string = buildOptionPath.getTargetBuildOptPath(this.moduleModel, this.targetName, 'sources');

      this.projectModel.getAllModules().forEach((moduleModel) => {
        allModuleModelCwd.push(moduleModel.getModule().getNodeDir());
      });

      // sources用来配置文件或者文件夹
      runtimeOnlyObj.sources.forEach((eachPath) => {
        const absolutePath = path.resolve(curModuleNodeDir, eachPath);
        const insideModuleFile = allModuleModelCwd.some((moduleModelCwd) => {
          return absolutePath.startsWith(moduleModelCwd);
        });
        if (!insideModuleFile) {
          outsideModuleFileErrorPaths.push(eachPath);
        }

        if (fse.existsSync(absolutePath)) {
          // 检查动态import配置的文件或文件夹是否真实存在
          if (fse.statSync(absolutePath).isFile() && !ValidateRegExp.DYNAMIC_IMPORT_FILE_SUFFIX_REG_EXP.test(FileUtil.getFileSuffix(eachPath))) {
            // 检查动态import配置的文件相对路径是否满足后缀格式要求
            suffixFileErrorPaths.push(eachPath);
          }
        } else {
          existFileErrorPaths.push(eachPath);
        }

        if (!absolutePath.startsWith(this.module.getNodeDir())) {
          // 检查模块内或模块间动态import配置是否正确
          acrossModuleErrorPaths.push(eachPath);
        }
      });
      if (existFileErrorPaths.length !== 0) {
        // runtimeOnly->sources配置的文件或文件夹不存在则报错退出
        _log.printErrorExit('SOURCES_NOT_FOUND', [this.moduleName, existFileErrorPaths, runtimeOnlySrcCfgPath]);
      }

      if (outsideModuleFileErrorPaths.length !== 0) {
        // 不允许配置工程内任一模块外(本模块及跨模块)的文件相对路径
        _log.printErrorExit('DYNAMIC_IMPORT_EXTERNAL_MODULE_PROHIBITED', [[...new Set(outsideModuleFileErrorPaths)], this.moduleName, runtimeOnlySrcCfgPath]);
      }

      if (suffixFileErrorPaths.length !== 0) {
        // runtimeOnly->sources配置的文件不满足以ets/ts后缀结尾则报错退出
        _log.printErrorExit('SOURCES_SUFFIX_INCORRECT', [suffixFileErrorPaths, this.moduleName, runtimeOnlySrcCfgPath]);
      }

      if (acrossModuleErrorPaths.length !== 0) {
        // strictMode-noExternalImportByPath为true时sources中的文件或文件夹的相对路径不允许跨模块配置
        if (noExternalImportByPath) {
          _log.printErrorExit('DYNAMIC_IMPORT_ACROSS_MODULE_PROHIBITED', [acrossModuleErrorPaths, this.moduleName, runtimeOnlySrcCfgPath]);
        } else {
          _log.warn(
            `Invalid dynamic import configuration [${acrossModuleErrorPaths}] ` +
              `in current module '${this.moduleName}'. \n` +
              '   Detail: The sources configuration of runtimeOnly in module is not allowed to configure' +
              ' across modules.\n' +
              `   at :${runtimeOnlySrcCfgPath}`,
          );
        }
      }
    }
    const moduleDependenciesList = Object.keys({...this.getDependencies(this.moduleModel, false),
      ...this.getDynamicDependencies(this.moduleModel)});
    const projectDependenciesList = Object.keys({...this.getDependencies(this.projectModel, false),
      ...this.getDynamicDependencies(this.projectModel)});
    if (runtimeOnlyObj.packages) {
      // packages用来配置动态依赖的包名：（1）依赖的包名必须在当前模块或工程级别的oh-package.json中的dependencies, dynamicDependencies中进行配置，进行校验若不存在进行报错
      // （2）不支持配置三方包中的某个文件路径，仅能支持配置包名
      if (!isSubset(getUnionSet(moduleDependenciesList, projectDependenciesList), runtimeOnlyObj.packages)) {
        // 包名,文件名形式的导入需要校验是否为本模块oh-package.json5中dependencies子集
        _log.printErrorExit(
          'DYNAMIC_IMPORT_PATH_INVALID',
          [this.moduleModel.getName(), this.profilePath],
          [[this.moduleModel.getName(), CommonConst.OH_PACKAGE_JSON5]],
        );
      }
    }
  }

  /**
   * 检查所有srcEntry字段是否以相对路径的形式配置
   * @private
   */
  protected checkAllSrcEntry() {
    const obj2srcEntryListMap = new Map<string, string[]>();
    const moduleJsonObj: ModuleOptObj = resModelLoader.getModuleJson(this.targetJsonPath);

    // module.json5->module.srcEntry
    if (moduleJsonObj.module.srcEntry) {
      obj2srcEntryListMap.set(this.MODULE_SRC_ENTRY, [moduleJsonObj.module.srcEntry]);
    }

    // module.json5->module.abilityObj.srcEntry
    const moduleAbilities = moduleJsonObj.module.abilities;
    const abilityObjSrcEntryList: string[] = [];
    if (moduleAbilities?.length) {
      for (const abilityItem of moduleAbilities) {
        if (abilityItem.srcEntry) {
          abilityObjSrcEntryList.push(abilityItem.srcEntry);
        }
      }

      obj2srcEntryListMap.set(this.MODULE_ABILITIES_SRC_ENTRY, abilityObjSrcEntryList);
    }

    // module.json5->module.extensionAbilities.srcEntry
    const extensionAbilities = moduleJsonObj.module.extensionAbilities;
    const extensionAbilityObjSrcEntryList: string[] = [];
    if (extensionAbilities) {
      for (const orgExtensionAbilityObj of extensionAbilities) {
        if (orgExtensionAbilityObj.srcEntry) {
          extensionAbilityObjSrcEntryList.push(orgExtensionAbilityObj.srcEntry);
        }
      }

      obj2srcEntryListMap.set(this.MODULE_EXTENSION_ABILITIES_SRC_ENTRY, extensionAbilityObjSrcEntryList);
    }

    // insight_intent.json->insightIntentsObj.srcEntry
    const insightIntentObjSrcEntryList: string[] = [];
    if (fse.existsSync(this.insightIntentJsonPath)) {
      const insightIntentDataJson = getJson5Obj(this.insightIntentJsonPath);
      // 适配新意图框架后，需要收集两个字段的srcEntry，并且两个字段都可能没有内容
      for (const intent of [...(insightIntentDataJson.insightIntents ?? []), ...(insightIntentDataJson.insightIntentsSrcEntry ?? [])]) {
        if (intent.srcEntry) {
          insightIntentObjSrcEntryList.push(intent.srcEntry);
        }
      }
      obj2srcEntryListMap.set(this.INSIGHT_INTENT_SRC_ENTRY, insightIntentObjSrcEntryList);
    }

    obj2srcEntryListMap.forEach((srcEntryList: string[] | undefined, objName: string) => {
      if (!srcEntryList?.length) {
        return;
      }

      srcEntryList?.forEach((srcEntry) => {
        if (!ValidateRegExp.RELATIVE_PATH_REG_EXP.test(srcEntry)) {
          _log.printErrorExit('SOURCE_ENTRY_INVALID_SYNTAX', [
            objName,
            objName === this.INSIGHT_INTENT_SRC_ENTRY ? this.insightIntentJsonPath : this.targetJsonPath,
          ]);
        }
      });
    });
  }

  private formJsonValidate() {
    this.formJsonPathArr.forEach((formJsonPath) => {
      ValidateUtil.submitSchemaCheckWork({
        moduleName: this.moduleName,
        filePath: formJsonPath,
        schemaPath: this.sdkInfo.getFormSchema(),
      });

      this.validateFormSrc(formJsonPath);
    });
  }

  async beforeAlwaysAction() {
    await super.beforeAlwaysAction();

    // 在之前校验warn 提示的信息，不能up-top-date
    this.checkEntryModuleJson();

    // 检查integratedHsp配置的是否合理
    this.checkIntegratedHspHsp();

    // 检查generateSharedTgz配置是否合理
    this.checkGenerateSharedTgz();

    // 检查transformLib字段是否合理;
    this.checkTransformLib();

    // 对pure har提前进行init
    moduleDependencyUtil.init(this.service, this.moduleModel, this.projectModel, this.isFaMode);
  }

  // 校验 modules.json5 中 uiSyntax字段，
  private checkEntryModuleJson(): void {
    const moduleJson: ModuleOptObj = parseJsonFile(this.targetJsonPath, true);
    if (moduleJson.module.uiSyntax) {
      const line = (moduleJson.module.uiSyntax as any)._line;
      const column = (moduleJson.module.uiSyntax as any)._column + 1;
      _log._file(this.targetJsonPath).warn(`uiSyntax has been deprecated.${os.EOL}         at ${this.targetJsonPath}:${line}:${column}`);
    }
  }

  /**
   * 获取指定profile的json文件路径
   * @param profile 指定的profile名称
   * @return 如果无法从传入参数解析出文件名，返回undefined，否则返回profile对应的json文件路径，
   * @throws 如果找不到对应的json文件或者资源目录配置无效，会抛出错误并退出程序
   */
  private getProfileJsonPath(profile: string): string | undefined {
    // 解析profile名称，获取对应的json文件名
    const profileJsonFileName = parsingProfileName(profile);
    if (!profileJsonFileName) {
      return undefined;
    }

    // 获取profile对应的json文件的完整路径
    const profileJsonFilePath = this.targetService.getTargetResourceBaseProfilePath(`${profileJsonFileName}.json`);

    // 如果无法获取到profile对应的json文件的完整路径，或者文件不存在，则抛出错误并退出程序
    if (!profileJsonFilePath || !fse.existsSync(profileJsonFilePath)) {
      _log.printErrorExit('PROFILE_NOT_FOUND', [`${profileJsonFileName}.json`], [[], [this.targetName], [`${profileJsonFileName}.json`]]);
    }

    // 返回profile对应的json文件的完整路径
    return profileJsonFilePath;
  }

  /**
   * 获取theme json的路径
   * @return string 返回theme文件的路径
   */
  private getSystemThemeJsonPath() {
    const systemTheme = this.targetModuleOptObj?.module.systemTheme;
    return this.getProfileJsonPath(systemTheme ?? '');
  }

  /**
   * hap: src/main/resources/base/profile/main_pages.json
   * hsp: src/main/resources/base/profile/main_pages.json
   * har: undefined
   * ohosTest: src/ohosTest/resources/base/profile/test_pages.json
   *
   * @private
   */
  private getPagesJsonPath(): string | undefined {
    const moduleOptObj: ModuleOptObj = parseJsonFile(this.targetJsonPath, false);
    const pages = moduleOptObj.module.pages;
    return this.getProfileJsonPath(pages);
  }

  /**
   * 获取启动窗口的json路径
   * @return {string[]} 返回启动窗口的json路径数组
   */
  private getStartWindowJsonPath(): string[] {
    // 解析目标json文件，获取模块配置对象
    const moduleOptObj: ModuleOptObj = parseJsonFile(this.targetJsonPath, false);

    // 获取模块配置对象中的能力列表
    const abilities = moduleOptObj.module?.abilities;
    if (!abilities) {
      return [];
    }
    const startWindowJsonPathArr: string[] = [];
    for (const ability of abilities) {
      if (ability.startWindow) {
        const startWindowJsonPath = this.getProfileJsonPath(ability.startWindow);

        // 如果启动窗口的json路径存在，则将其添加到启动窗口json路径数组中
        startWindowJsonPath ? startWindowJsonPathArr.push(startWindowJsonPath) : null;
      }
    }
    return startWindowJsonPathArr;
  }

  private pagesJsonValidate() {
    const pagesJsonPath = this.getPagesJsonPath();
    if (pagesJsonPath === undefined) {
      return;
    }
    ValidateUtil.submitSchemaCheckWork({
      moduleName: this.moduleName,
      filePath: pagesJsonPath,
      schemaPath: this.sdkInfo.getPageSchema(),
    });
  }

  /**
   * startWindowJ.json文件schema校验
   * @private
   */
  private startWindowJsonValidate() {
    this.startWindowJsonPathArr.forEach((startWindowJsonPath: string) => {
      ValidateUtil.submitSchemaCheckWork({
        moduleName: this.moduleName,
        filePath: startWindowJsonPath,
        schemaPath: this.sdkInfo.getStartWindowSchema(),
      });
    });
  }

  /**
   * startWindowJ.json文件schema校验
   * @private
   */
  private systemThemeJsonValidate() {
    if (!this.systemThemeJsonPath) {
      return;
    }
    ValidateUtil.submitSchemaCheckWork({
      moduleName: this.moduleName,
      filePath: this.systemThemeJsonPath,
      schemaPath: this.sdkInfo.getSystemThemeSchema(),
    });
  }

  /**
   * routerMap.json文件schema校验
   * @private
   */
  private routerMapJsonValidate() {
    this.checkResReferenceConfig(CommonConst.ROUTER_MAP);
    if (!this.routerMapJsonPath || !fse.existsSync(this.routerMapJsonPath)) {
      return;
    }

    ValidateUtil.submitSchemaCheckWork({
      moduleName: this.moduleName,
      filePath: this.routerMapJsonPath,
      schemaPath: this.sdkInfo.getRouterMapSchema(),
    });
  }

  /**
   * syscap.json文件schema校验
   * @private
   */
  private sysCapValidate(): void {
    if (this.targetData.isHarmonyOS() || !fse.existsSync(this.syscapJsonPath)) {
      return;
    }

    ValidateUtil.submitSchemaCheckWork({
      moduleName: this.moduleName,
      filePath: this.syscapJsonPath,
      schemaPath: this.sdkInfo.getSysCapSchema(),
    });
  }

  private hvigorConfigValidate() {
    const hvigorConfigSchemaPath = BuildProfileSchemaFileConst.HVIGOR_CONFIG_SCHEMA_PATH;
    if (!fs.existsSync(this.hvigorConfigPath) || !fs.existsSync(hvigorConfigSchemaPath)) {
      return;
    }

    ValidateUtil.submitSchemaCheckWork({
      moduleName: this.projectModel.getName(),
      filePath: this.hvigorConfigPath,
      schemaPath: hvigorConfigSchemaPath,
    });
  }

  private pacFileValidate() {
    if (this.service.getModuleModel().isHapModule()) {
      return;
    }
    const pacSchemaPath = this.sdkInfo.getPacSchema();
    if (pacFileValidate(this.moduleName, this.originalModulePacJsonPath, pacSchemaPath)) {
      fse.copySync(this.originalModulePacJsonPath, this.processedPacJsonPath);
    }
  }

  /**
   * 1. validate form file is under current module
   * 2. validate form file exists
   *
   * @param formJsonPath string
   */
  private validateFormSrc(formJsonPath: string): void {
    const formConfigObj: FormConfigJson.FormConfigJsonObj = parseJsonFile(formJsonPath, false);
    if (formConfigObj.forms === undefined) {
      return;
    }

    for (const form of formConfigObj.forms) {
      if (!form.src) {
        _log.printErrorExit('FORM_SRC_FIELD_MISSING', [formJsonPath]);
      }
      const moduleDir = this.moduleModel.getProjectDir();
      const parentDir = path.resolve(moduleDir, 'src/main');
      const formPath = FileUtil.convertToAbsolutePath(form.src, parentDir);
      if (!path.normalize(formPath).startsWith(path.normalize(moduleDir))) {
        _log.printErrorExit('FORM_SRC_INVALID', [form.src, moduleDir, formJsonPath]);
      }

      const isArkTsWidget = form.uiSyntax === 'arkts';
      if (!this.isValidWidget(isArkTsWidget, parentDir, formPath)) {
        _log.printErrorExit('FORM_SRC_NOT_FOUND', [form.src, formJsonPath]);
      }
    }
  }

  /**
   * 校验module.json中的mainElement
   * 1、非模块（模块未空），或新版ohosTest模块不进行校验。
   * 2、支持免安装特性的元服务，mainElement不能为空。
   * 3、mainElement的ability需包含icon和label字段。 -- 此规格变更，允许不包含这两个字段。
   * @returns
   */
  private validateMainElement(): void {
    // 模块不为空，且不是新版的ohosTest模块。
    if (this.targetModuleOptObj === undefined || this.isNewOhosTestTemplate()) {
      return;
    }

    // 支持免安装特性的元服务，mainElement不能为空
    const mainElement = this.targetModuleOptObj.module.mainElement;
    if (this.targetModuleOptObj.module.installationFree && mainElement === undefined) {
      _log.printErrorExit('EMPTY_MAIN_ELEMENT', [this.targetJsonPath]);
    }
  }

  /**
   * 是否是新的ohosTest模板。
   * 说明：ohosTest原来工程模板里有openHarmonyTestRunner.ets这些模板文件，新模板是把testrunner等目录移走了。
   * @private
   */
  private isNewOhosTestTemplate(): boolean {
    if (this.targetName !== DefaultTargetConst.OHOS_TEST_TARGET) {
      return false;
    }

    return isTemplatesAfterSourceCodeMigration(this.moduleModel.getSourceRootByTargetName(DefaultTargetConst.OHOS_TEST_TARGET));
  }

  /**
   * AtomicService相关校验
   *
   * @private
   */
  validateAtomicService() {
    // 如果不是元服务则退出该校验
    if (!this.isAtomicServiceProject()) {
      _log.debug('current product is not Atomic service.');
      return;
    }

    const bundleType = this.getBundleType();
    const installationFree = this.targetModuleOptObj?.module?.installationFree;
    const externalNativeOptions = this.targetService.getBuildOption().externalNativeOptions;
    const errorFilePath = this.getAtomicServiceErrorPath(bundleType, installationFree);

    // 元服务只支持HarmonyOS
    if (!this.targetData.isHarmonyOS()) {
      this.validateSpecificField(bundleType, installationFree);
      _log.printErrorExit('ATOMIC_SERVICE_INVALID_RUNTIME_OS', [this.projectModel.getProfilePath()]);
    }

    // 元服务只支持api11及以上
    if (!limitMinApiVersion(this.targetData, ApiVersion.API_VERSION_10)) {
      _log.printErrorExit('ATOMIC_SERVICE_UNSUPPORTED_API', [this.projectProfilePath]);
    }

    // 元服务不支持使用native方式开发
    if (externalNativeOptions) {
      _log.printErrorExit('ATOMIC_SERVICE_UNSUPPORTED_NATIVE', [this.projectProfilePath]);
    }

    // 如果当前模块为har或hsp则退出该校验
    const moduleType = this.service.getModuleModel().getModuleType();
    if (moduleType === ModuleType.Har || moduleType === ModuleType.Shared) {
      return;
    }

    // 元服务不支持js卡片开发
    this.formJsonPathArr.forEach((formConfigJson: string) => {
      const formConfigObj: FormConfigJson.FormConfigJsonObj = parseJsonFile(formConfigJson, false);
      if (formConfigObj.forms) {
        for (const form of formConfigObj.forms) {
          if (!form.uiSyntax || form.uiSyntax !== 'arkts') {
            _log.printErrorExit('ATOMIC_SERVICE_JS_WIDGET', [formConfigJson]);
          }
        }
      }
    });

    if (
      this.targetModuleOptObj?.module?.mainElement === undefined &&
      !(
        this.targetName === DefaultTargetConst.OHOS_TEST_TARGET &&
        isTemplatesAfterSourceCodeMigration(this.moduleModel.getSourceRootByTargetName(DefaultTargetConst.OHOS_TEST_TARGET))
      )
    ) {
      _log.printErrorExit('EMPTY_MAIN_ELEMENT', [this.targetJsonPath]);
    }
  }

  /**
   * 获取元服务校验报错文件路径
   *
   * @param bundleType  app.json5-bundleType
   * @param installationFree  module.json5-installationFree
   * @private
   */
  private getAtomicServiceErrorPath(bundleType: string | undefined, installationFree: boolean | undefined): string {
    let filePath = '';
    if (bundleType === undefined || bundleType === 'app') {
      if (installationFree) {
        filePath = this.targetJsonPath;
      }
    }
    if (bundleType === BundleType.ATOMIC_SERVICE || !installationFree) {
      filePath = this.appJson5Path;
    }
    return filePath;
  }

  /**
   * 指定bundleType和installationFree字段校验
   *
   * @param bundleType  app.json5-bundleType
   * @param installationFree  module.json5-installationFree
   * @private
   */
  private validateSpecificField(bundleType: string | undefined, installationFree: boolean | undefined): void {
    // 以前只有在同时满足bundleType为元服务和installationFree为True的时候才认为应用是元服务，所以才有此处判断逻辑，为了兼容性保留此处逻辑保持不变
    if (bundleType === BundleType.ATOMIC_SERVICE && installationFree) {
      _log.printErrorExit('ATOMIC_SERVICE_INVALID_RUNTIME_OS', [this.projectModel.getProfilePath()]);
    }
  }

  private validateMockConfig() {
    const mockConfig: any = getJson5Obj(this.moduleModel.getMockConfigPath());
    if (!mockConfig) {
      return;
    }
    Object.values(mockConfig).forEach((value: any) => {
      const source = value.source;
      if (source) {
        const mockSourceFile = path.resolve(this.moduleModel.getProjectDir(), source);
        if (!fse.existsSync(mockSourceFile)) {
          _log.printErrorExit('SOURCE_NOT_FOUND', [mockSourceFile, this.moduleModel.getMockConfigPath()]);
        }
      } else {
        _log.printErrorExit('SOURCE_FILED_EMPTY', [this.moduleModel.getMockConfigPath()]);
      }
    });
  }

  protected getJsonProfileByModel(): JsonProfile {
    const jsonFile = resModelLoader.getModuleJson(this.targetJsonPath);
    return {
      jsonFilePath: this.targetJsonPath,
      profile: jsonFile,
      deviceTypes: jsonFile.module.deviceTypes,
      deviceConfig: CommonConst.DEVICE_TYPES,
      configurationProfile: CommonConst.MODULE_JSON5,
    };
  }

  private hvigorFileConfigValidate() {
    const projectConfig = projectOhosConfigManager.getConfig();
    if (projectConfig !== undefined) {
      validateOhosProjectConfig(projectConfig, `${this.module.getProject().getBuildFilePath()}.ts`);
    }
    const config = moduleOhosConfigManager.getConfig(this.moduleName);
    if (config !== undefined) {
      if (this.moduleModel.isHarModule()) {
        validateOhosHarModuleConfig(config, `${this.module.getBuildFilePath()}.ts`);
      } else {
        validateOhosModuleConfig(config, `${this.module.getBuildFilePath()}.ts`);
      }
    }
  }


  /**
   * 根据ArkTS1.2的规格进行校验(只在ArkTS1.2下才会执行):
   * 1. useNormalizedOHMUrl需设为true
   *
   * @protected
   */
  protected doValidateForStaticArkTS() {

    const arkTSVersion = this.targetService.getSelfArkTSVersion();
    if (arkTSVersion !== ArkTSVersionConst.ARKTS1_2){
      return;
    }

    // useNormalizedOHMUrl需设为true
    const currentOHMUrl = this.targetService.getBuildOption()?.strictMode?.useNormalizedOHMUrl;
    if (!currentOHMUrl) {
      _log.printErrorExit(
        'STATIC_ARKTS_OHMURL_RESTRICTION',
        [this.moduleModel.getName(), this.projectModel.getProject().getBuildProfilePath()],
        [[], [this.moduleModel.getName()]],
      );
    }
  }

  /**
   * 检查工程使用OHMUrl的api版本需>api11
   * 检查当前工程的OHMURL解析方式依赖的hsp包是否支持
   *
   * @private
   */
  private checkOHMURL() {
    const currentOHMUrl = this.targetService.getBuildOption()?.strictMode?.useNormalizedOHMUrl;
    ohosTrace.traceUseNormalizedOHMUrl(currentOHMUrl);

    // 检查工程使用OHMUrl的api版本需>api11
    if (currentOHMUrl && !limitMinApiVersion(this.targetData, ApiVersion.API_VERSION_11)) {
      _log.printErrorExit('USENORMAILZEDOHMURL_CAN_ONLY_BE_USED_IN_API12', [this.projectModel.getProfilePath()]);
    }

    // 检查当前工程的OHMURL解析方式依赖的hsp包是否支持
    const allDependencies = this.targetService.getModuleService().getAllDependencies();
    const packages: string[] = [];
    for (const dependency of allDependencies) {
      if (!this.isEqualOHMUrl(dependency, currentOHMUrl)) {
        packages.push(dependency.getPackageName());
      }
    }
    if (packages.length > 0) {
      _log.printErrorExit('USENORMAILZEDOHMURL_DO_NOT_MATCH', [packages.join(), String(currentOHMUrl)], [[packages.join()]]);
    }
  }

  /**
   * 判断OHMUrl是否一致，如果是本地模块默认一致，如果是非本地模块则需要判断一致性，只对hsp模块进行判断
   *
   * @param dependency
   * @param currentOHMUrl
   * @private
   */
  private isEqualOHMUrl(dependency: Dependency, currentOHMUrl: boolean | undefined) {
    if (dependency.getDependencyType() === DependencyType.DEPENDENCY_TYPE_HSP) {
      return DependencyManager.isLocalDependency(dependency, this.moduleModelNodePaths) || !!currentOHMUrl === !!dependency.getUseNormalizedOHMUrl();
    } else {
      return true;
    }
  }

  private getExtendSourceDirsValidateResult(): IExtendSourceValidateResult {
    let cause = '';
    let detail = '';
    const targetData = this.targetService.getTargetData();
    const sourceDirs = targetData.getTargetOpt().source?.sourceRoots;
    if (!sourceDirs?.length) {
      return { isValid: true, cause, detail };
    }
    const modulePath = this.pathInfo.getModulePath();
    const moduleSrcPath = this.pathInfo.getModuleSrcPath();
    const depth = this.pathInfo.getModuleSrcMainPath().split(path.sep).length;
    const targetOptions = this.moduleModel.getTargetOptions();
    const targetIndex = targetOptions.findIndex((targetOption) => targetOption.name === targetData.getTargetName());
    const xpath = `targets[${targetIndex}].source.sourceRoots`;
    const sourceDirsSet = new Set<string>();
    for (const dir of sourceDirs) {
      if (path.isAbsolute(dir)) {
        cause = `Invalid value '${dir}' in module '${this.moduleModel.getName()}'.`;
        detail = `Make sure the values of '${xpath}' are relative paths.`;
        break;
      }
      let sourceDir = path.resolve(modulePath, dir);
      if (!fse.existsSync(sourceDir)) {
        cause = `Path '${dir}' not found in module '${this.moduleModel.getName()}'.`;
        detail = `Make sure the values of '${xpath}' are valid paths.`;
        break;
      }
      let stat = fse.lstatSync(sourceDir);

      // 软链接，获取其真实路径
      if (stat.isSymbolicLink()) {
        try {
          sourceDir = fse.realpathSync(sourceDir);
          stat = fse.lstatSync(sourceDir);
        } catch {
          // 软链接失效
          cause = `Path '${dir}' not found in module '${this.moduleModel.getName()}'.`;
          detail = `Make sure the values of '${xpath}' are valid paths.`;
          break;
        }
      }
      if (!stat.isDirectory()) {
        cause = `Invalid value '${dir}' in module '${this.moduleModel.getName()}'.`;
        detail = `Make sure the values of '${xpath}' are valid directory paths.`;
        break;
      }
      if (!FileUtil.isSubDir(moduleSrcPath, sourceDir) || sourceDir.split(path.sep).length !== depth) {
        cause = `Invalid value '${dir}' in module '${this.moduleModel.getName()}'.`;
        detail = `Make sure the values of '${xpath}' are subdirectories of '${moduleSrcPath}'.`;
        break;
      }
      if (sourceDirsSet.has(sourceDir)) {
        cause = `Invalid value '${dir}' in module '${this.moduleModel.getName()}'.`;
        detail = `Make sure the values of '${xpath}' are unique.`;
        break;
      }
      sourceDirsSet.add(sourceDir);
    }
    return { isValid: !(cause && detail), cause, detail };
  }

  protected checkExtendSourceDirs() {
    const { isValid, cause, detail } = this.extendSourceValidateResult;
    if (!isValid) {
      _log._buildError(cause)._detail(detail)._file(this.profilePath)._printErrorAndExit();
    }
  }

  /**
   * 如果integratedHsp字段hap中配置了则warn告警
   * 如果配置了integratedHsp为true但是useNormalizedOHMUrl为false或者没有配置的话，error报错
   *
   * @private
   */
  private checkIntegratedHspHsp() {
    const integratedHsp = this.targetService.getBuildOption().arkOptions?.integratedHsp;
    const useNormalizedOHMUrl = this.targetService.getBuildOption().strictMode?.useNormalizedOHMUrl;
    if (integratedHsp && !limitMinApiVersion(this.targetData, ApiVersion.API_VERSION_11)) {
      _log.printErrorExit('INTEGRATED_HSP_UNSUPPORTED_API', [this.moduleModel.getParentProject().getProfilePath()]);
    }
    if (integratedHsp && !useNormalizedOHMUrl) {
      _log.printErrorExit('INTEGRATED_HSP_REQUIRED_NORMALIZED_OHMURL', [this.projectModel.getProfilePath()]);
    }
    if (integratedHsp && this.service.getModuleModel().isHapModule()) {
      _log.warn(`The integratedHsp does not take effect in the HAP ${this.moduleModel.getName()}.`);
    }
  }

  /**
   * 如果generateSharedTgz字段hap中配置了则warn告警
   *
   * @private
   */
  private checkGenerateSharedTgz() {
    const generateSharedTgz = this.targetService.getBuildOption().generateSharedTgz;
    if (typeof generateSharedTgz !== 'undefined'  && this.service.getModuleModel().isHapModule()) {
      _log.warn(`The generateSharedTgz does not take effect in the HAP ${this.moduleModel.getName()}.`);
    }
  }

  /**
   *  校验配置的transformLib是否合法
   *
   */
  private checkTransformLib() {
    const transformLib = this.targetService.getBuildOption()?.arkOptions?.transformLib;
    if (transformLib) {
      ohosTrace.traceIsUseTransformLib(this.moduleName);
      if (!InjectUtil.isInTest() && this.targetService.isSourceCodeHar()) {
        _log.warn("Only the byte code har supports to configure the 'transformLib' field.");
      }
      if (path.isAbsolute(transformLib)) {
        _log.printErrorExit('TRANSFORM_LIB_SHOULD_BE_RELATIVE_PATH', [path.resolve(this.pathInfo.getModulePath(), 'build-profile.json5')]);
      }
      const absolutePath = path.resolve(this.pathInfo.getModulePath(), transformLib);
      if (fse.existsSync(absolutePath)) {
        if (!fse.statSync(absolutePath).isFile()) {
          _log.printErrorExit('TRANSFORM_LIB_IS_NOT_FILE', [transformLib, path.resolve(this.pathInfo.getModulePath(), 'build-profile.json5')]);
        }
        this.checkTransformLibFileType(absolutePath.substring(absolutePath.lastIndexOf('.') + 1));
      } else {
        _log.printErrorExit('TRANSFORM_LIB_FILE_NOT_EXIST', [transformLib, path.resolve(this.pathInfo.getModulePath(), 'build-profile.json5')]);
      }
    }
  }

  private checkTransformLibFileType(fileType: string) {
    if (isWindows()) {
      if (fileType !== 'dll') {
        _log.printErrorExit('TRANSFORM_LIB_REQUIRES_A_X_FILE', ['.dll', 'Windows', path.resolve(this.pathInfo.getModulePath(), 'build-profile.json5')]);
      }
    }
    if (isMac() || isLinux()) {
      if (fileType !== 'so') {
        _log.printErrorExit('TRANSFORM_LIB_REQUIRES_A_X_FILE', ['.so', 'Mac or Linux', path.resolve(this.pathInfo.getModulePath(), 'build-profile.json5')]);
      }
    }
  }

  /**
   *  检查app.json5 下面configuration 字段的合法性
   * @protected
   */
  protected checkAppConfiguration() {
    const appJsonObj: AppJson.AppOptObj = resModelLoader.getAppJson(this.appJson5Path);
    const configuration = appJsonObj.app.configuration;
    if (!configuration) {
      return;
    }
    const configPath = this.getConfigurationFilePath(configuration);
    if (!configPath) {
      return;
    }
    const configurationConfigSrcPath = buildOptionPath.getAppConfigPath(this.appJson5Path, 'configuration');
    if (!fse.existsSync(configPath)) {
      _log.printErrorExit('CONFIG_FILE_NOT_FOUND', [configurationConfigSrcPath]);
    }
    const appConfigurationSchema = this.sdkInfo.getAppConfigurationSchema();
    if (!fse.existsSync(appConfigurationSchema)) {
      _log.printErrorExit('SCHEMA_FILE_CANNOT_BE_FOUND', [appConfigurationSchema]);
    }
    ValidateUtil.submitSchemaCheckWork({
      moduleName: this.projectModel.getName(),
      filePath: configPath,
      schemaPath: appConfigurationSchema,
    });
  }

  protected getConfigurationFilePath(configuration: string) {
    const configurationName = parsingProfileName(configuration);
    if (!configurationName) {
      return '';
    }
    const resourcePath = (this.projectModel as ProjectModelImpl).getAppRes().getResourcePath();
    // 暂时不考虑国际化的问题
    return path.resolve(resourcePath, 'base', 'profile', `${configurationName}.json`);
  }

  protected addConfigurationToInput(declareInputsMap: Map<string, TaskInputValue>) {
    const configuration = resModelLoader.getAppJson(this.appJson5Path).app?.configuration;
    declareInputsMap.set('configuration', configuration ?? '');
    if (configuration && fse.existsSync(this.getConfigurationFilePath(configuration))) {
      const configurationFileJson = Json5Reader.getJson5Obj(this.getConfigurationFilePath(configuration));
      declareInputsMap.set('configurationFileJson', JSON.stringify(configurationFileJson) ?? '');
    } else {
      declareInputsMap.set('configurationFileJson', '');
    }
    return declareInputsMap;
  }

  /**
   * 校验如"routerMap":"$profile:xxx"等资源引用方式的配置,若对应文件不存在则报错
   * @param configField
   * @private
   */
  private checkResReferenceConfig(configField: string) {
    const moduleJsonObj: ModuleOptObj = resModelLoader.getModuleJson(this.targetJsonPath);
    const checkConfigField: string = moduleJsonObj.module[configField] as string;
    if (!checkConfigField) {
      return;
    }

    const checkConfigFieldProfileName = parsingProfileName(checkConfigField);
    if (!checkConfigFieldProfileName) {
      return;
    }

    const filePath = this.targetService.getTargetResourceBaseProfilePath(`${checkConfigFieldProfileName}.json`);
    if (!filePath || !fse.existsSync(filePath)) {
      _log.printErrorExit('FIELD_FILE_NOT_FOUND', [configField, moduleOptionPathInfo.getModuleOptPath(this.targetJsonPath, configField)]);
    }
  }

  /**
   * 仅byteCodeHar支持bundleDependencies
   * @private
   */
  private checkBundledDependencies(): void {
    const bundledDependencies = this.targetService.isBundledDependencies();
    if (!bundledDependencies) {
      return;
    }

    const useNormalizedOHMUrl = this.targetService.getBuildOption()?.strictMode?.useNormalizedOHMUrl;
    const byteCodeHar = this.targetService.getByteCodeHar(useNormalizedOHMUrl, this.targetService.getBuildOption()?.arkOptions?.byteCodeHar);
    if (!byteCodeHar) {
      _log.printErrorExit('BYTE_CODE_HAR_UNSUPPORTED', [this.projectModel.getProfilePath()]);
    }
  }

  /**
   * 检查当前api版本har/hsp是否支持UIAbility
   * 该功能仅在api≥14支持,一体化IDE中sdk与hvigor配套,若配置compatibleApiVersion小于14则抛出告警
   * @private
   */
  private checkUIAbility(): void {
    const targetJsonPath = this.targetJsonPath;
    const moduleOptObj: ModuleOptObj = resModelLoader.getModuleJson(targetJsonPath);
    if (!moduleOptObj.module?.abilities?.length || (!this.moduleModel.isHspModule() && !this.moduleModel.isHarModule())) {
      return;
    }

    const apiMeta: ProjectBuildProfile.ProductApiMeta = this.targetData.getApiMeta();
    if (apiMeta.compatibleSdkVersion.version < ApiVersion.API_VERSION_14) {
      _log.warn(
        'The UIAbility configuration for HAR or HSP is only supported on the versions which API is greater than or equal to 14.' +
          ' Otherwise it may occur some problems.',
      );
    }
  }

  private checkSdkVersionMatchLazyImport(): void {
    // autoLazyImport未配置或者为false无需校验
    if (!this.targetService.getBuildOption()?.arkOptions?.autoLazyImport) {
      return;
    }

    if (
      this.compatibleApiVersion < ApiVersion.API_VERSION_12 ||
      (this.compatibleApiVersion === 12 && (this.compatibleSdkVersionStage === 'beta1' || this.compatibleSdkVersionStage === 'beta2'))
    ) {
      _log.printErrorExit('AUTO_LAZY_IMPORT_CANNOT_BE_CONFIGURED_FOR_THE_CURRENT_API_VERSION');
    }
  }

  /**
   * Iterate dynamicDependency list
   * @private
   */
  private iterateDependencies(dependencies: string[]): string[] {
    const harDependencies = this.service.getHarDependencies();
    const otherDependencies = this.service.getOtherDependencies();
    const warnDependencies: string[] = [];

    dependencies.forEach(dependency => {
      if (harDependencies.find((har) => har.getDependencyName() === dependency) ||
        otherDependencies.find((other) => other.getDependencyName() === dependency)) {
        warnDependencies.push(dependency);
      }
    });

    return warnDependencies;
  }

  /**
   * Check dynamicDependency types and issue warning for HAR/other types
   * @private
   */
  private checkDynamicDependencyTypes() {
    const moduleDependenciesList = Object.keys(this.getDynamicDependencies(this.moduleModel));
    const projectDependenciesList = Object.keys(this.getDynamicDependencies(this.projectModel));

    const warnDependencies = [...this.iterateDependencies(moduleDependenciesList), ...this.iterateDependencies(projectDependenciesList)];

    if (warnDependencies.length !== 0) {
      _log.warn(
        'dynamicDependencies is intended for dynamically distributed HSP dependencies. ' +
        `It is not recommended to configure HAR packages or third-party dependencies. Using package '${warnDependencies}'.`
      );
    }
  }

  /**
   * 检查在HAP或HAR模块中是否将includeAppScopeRes设置为false
   * 如果有，则需要提示开发者该配置项对HAP和HAR模块不生效
   */
  private checkIncludeAppScopeResInHapOrHar() {
    if ((this.moduleModel.isHapModule() || this.moduleModel.isHarModule()) && this.targetService.getBuildOption().resOptions?.includeAppScopeRes === false) {
      _log.warn(
        `'IncludeAppScopeRes'  configured at 'build-profile.json5' only works for HSP module, and will not take effect in HAP/HAR module '${this.moduleModel.getName()}.`
      );
    }
  }
}
